<script lang="ts">
import {
  defineComponent,
  nextTick,
  onMounted,
  onBeforeUnmount,
  reactive,
  ref,
  toRefs,
  watch
} from 'vue'
import type { PropType } from 'vue'

interface PageTableProps {
  pageSize: number,
  pageNum: number,
  pageSizes: number[],
  total: number,
  layout: string,
  tableData: any[],
  selectMode: boolean,
  rowKey: string,
  selectedKeyList: string[],
  hasQuery: boolean,
  hasOperation: boolean,
  hasPagination: boolean,
  selectedList: any[],
  borderMode: boolean,
}

export default defineComponent({
  name: 'PageTable',
  props: {
    pageSize: {
      type: Number,
      required: true
    },
    pageNum: {
      type: Number,
      required: true
    },
    pageSizes: {
      type: Array as PropType<number[]>,
      default: () => [10, 20, 50, 100, 500]
    },
    total: {
      type: Number,
      default: 0
    },
    layout: {
      type: String,
      default: 'total, sizes, prev, pager, next, jumper'
    },
    tableData: {
      type: Array as PropType<any[]>,
      default: () => []
    },
    selectMode: {
      type: Boolean,
      default: false
    },
    rowKey: {
      type: String,
      default: 'id'
    },
    selectedList: {
      type: Array as PropType<any[]>,
      default: () => []
    },
    hasQuery: {
      type: Boolean,
      default: true
    },
    hasOperation: {
      type: Boolean,
      default: true
    },
    hasPagination: {
      type: Boolean,
      default: true
    },
    borderMode: {
      type: Boolean,
      default: false
    }
  },
  emits: ['update:pageSize', 'update:pageNum', 'update:selectedList', 'select'],
  setup(props: PageTableProps, { emit }) {
    const state = reactive({
      heightContainer: 0,
      heightQuery: 0,
      heightOperation: 0,
      heightTable: 0,
      heightPagination: 0,
      paginationPageSize: 0,
      paginationPageNum: 0,
      multipleSelection: [] as any[]
    })

    const refContainer = ref<HTMLDivElement | null>(null)
    const refQueryBox = ref<HTMLDivElement | null>(null)
    const refOperationBox = ref<HTMLDivElement | null>(null)
    const refTableBox = ref<HTMLDivElement | null>(null)
    const refPaginationBox = ref<HTMLDivElement | null>(null)

    onMounted(() => {
      handleCalculateHeight()
      window.addEventListener('resize', handleCalculateHeight)
      state.paginationPageSize = props.pageSize
      state.paginationPageNum = props.pageNum
      state.multipleSelection = props.selectedList
    })

    onBeforeUnmount(() => {
      window.removeEventListener('resize', () => {})
    })

    watch(() => props.pageSize, (e) => {
      state.paginationPageSize = e
    })

    watch(() => props.pageNum, (e) => {
      state.paginationPageNum = e
    })

    watch(() => props.selectedList, (e) => {
      state.multipleSelection = e
    }, {
      deep: true,
      immediate: true,
    })

    watch(() => state.paginationPageSize, (e) => {
      emit('update:pageSize', e)
    })

    watch(() => state.paginationPageNum, (e) => {
      emit('update:pageNum', e)
    })

    watch(() => state.multipleSelection, (e) => {
      emit('update:selectedList', e)
    }, {
      deep: true,
      immediate: true,
    })

    const handleCalculateHeight = () => {
      nextTick(() => {
        if(refContainer.value) {
          state.heightContainer = refContainer.value.clientHeight
        }
        if(refQueryBox.value) {
          state.heightQuery = refQueryBox.value.clientHeight + 12
        }
        if(refOperationBox.value) {
          state.heightOperation = refOperationBox.value.clientHeight + 12
        }
        if(refPaginationBox.value) {
          state.heightPagination = refPaginationBox.value.clientHeight + 12
        }
        state.heightTable = state.heightContainer - state.heightQuery - state.heightOperation - state.heightPagination
      })
    }

    const handlePageSizeChange = (e: number) => {
      state.paginationPageNum = 1
      state.paginationPageSize = e
    }

    const handlePageNumChange = (e: number) => {
      state.paginationPageNum = e
    }

    const handleSelectionChange = (e: any[]) => {
      state.multipleSelection = e
      emit('select')
    }

    return {
      ...toRefs(state),
      refContainer,
      refQueryBox,
      refOperationBox,
      refTableBox,
      refPaginationBox,
      handlePageSizeChange,
      handlePageNumChange,
      handleSelectionChange
    }
  }
})
</script>

<template>
  <div ref="refContainer" class="page-table-container">
    <div ref="refQueryBox" v-if="hasQuery" :class="borderMode ? '--border-mode' : ''" class="page-table--query-box">
      <el-form label-position="top">
        <el-space size="small" wrap>
          <slot name="query" />
        </el-space>
      </el-form>
    </div>
    <div ref="refOperationBox" v-if="hasOperation" :class="borderMode ? '--border-mode' : ''" class="page-table--operation-box">
      <div class="--left">
        <el-space size="small">
          <slot name="operationLeft" />
        </el-space>
      </div>
      <div class="--right">
        <el-space size="small">
          <slot name="operationRight" />
        </el-space>
      </div>
    </div>
    <div ref="refTableBox" class="page-table--table-box" :style="{ height: heightTable + 'px' }">
      <el-table :data="tableData" :row-key="rowKey" :border="borderMode" height="100%" style="width: 100%;" @selection-change="handleSelectionChange">
        <el-table-column v-if="selectMode" type="selection" width="55" />
        <slot name="table" />
      </el-table>
    </div>
    <div ref="refPaginationBox" v-if="hasPagination" :class="borderMode ? '--border-mode' : ''" class="page-table--pagination-box">
      <el-pagination v-model:page-size="paginationPageSize"
                     v-model:current-page="paginationPageNum"
                     :pageSizes="pageSizes"
                     :total="total"
                     :layout="layout"
                     @size-change="handlePageSizeChange"
                     @current-change="handlePageNumChange" />
    </div>
  </div>
</template>

<style lang="scss">
.page-table-container {
  height: 100%;

  .page-table--query-box {
    margin-bottom: 12px;
  }

  .page-table--operation-box {
    margin-bottom: 12px;
    display: flex;
    justify-content: space-between;
  }

  .page-table--table-box {

  }

  .page-table--pagination-box {
    margin-top: 12px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
  }
}
</style>
